package io.noties.markwon.plugin.latex

import android.graphics.drawable.Drawable
import androidx.annotation.ColorInt
import androidx.annotation.Px
import ru.noties.jlatexmath.JLatexMathDrawable

/**
 * @since 4.3.0
 */
abstract class JLatexMathTheme {
    /**
     * Moved from [JLatexMathPlugin] in `4.3.0` version
     *
     * @since 4.0.0
     */
    interface BackgroundProvider {
        fun provide(): Drawable
    }

    /**
     * Special immutable class to hold padding information
     */
    class Padding(val left: Int, val top: Int, val right: Int, val bottom: Int) {
        override fun toString(): String {
            return "Padding{" +
                    "left=" + left +
                    ", top=" + top +
                    ", right=" + right +
                    ", bottom=" + bottom +
                    '}'
        }

        companion object {
            fun all(value: Int): Padding {
                return Padding(value, value, value, value)
            }

            fun symmetric(vertical: Int, horizontal: Int): Padding {
                return Padding(horizontal, vertical, horizontal, vertical)
            }

            /**
             * @since 4.5.0
             */
            fun of(left: Int, top: Int, right: Int, bottom: Int): Padding {
                return Padding(left, top, right, bottom)
            }
        }
    }

    /**
     * @return text size in pixels for **inline LaTeX**
     * @see .blockTextSize
     */
    @Px
    abstract fun inlineTextSize(): Float

    /**
     * @return text size in pixels for **block LaTeX**
     * @see .inlineTextSize
     */
    @Px
    abstract fun blockTextSize(): Float
    abstract fun inlineBackgroundProvider(): BackgroundProvider?
    abstract fun blockBackgroundProvider(): BackgroundProvider?

    /**
     * @return boolean if **block LaTeX** must fit the width of canvas
     */
    abstract fun blockFitCanvas(): Boolean

    /**
     * @return horizontal alignment of **block LaTeX** if [.blockFitCanvas]
     * is enabled (thus space for alignment is available)
     */
    @JLatexMathDrawable.Align
    abstract fun blockHorizontalAlignment(): Int
    abstract fun inlinePadding(): Padding?
    abstract fun blockPadding(): Padding?
    @ColorInt
    abstract fun inlineTextColor(): Int
    @ColorInt
    abstract fun blockTextColor(): Int
    class Builder internal constructor(
        val textSize: Float,
        val inlineTextSize: Float,
        val blockTextSize: Float
    ) {
        var backgroundProvider: BackgroundProvider? = null
        var inlineBackgroundProvider: BackgroundProvider? = null
        var blockBackgroundProvider: BackgroundProvider? = null
        var blockFitCanvas = true

        // horizontal alignment (when there is additional horizontal space)
        var blockHorizontalAlignment = JLatexMathDrawable.ALIGN_CENTER
        var padding: Padding? = null
        var inlinePadding: Padding? = null
        var blockPadding: Padding? = null
        var textColor = 0
        var inlineTextColor = 0
        var blockTextColor = 0
        fun backgroundProvider(backgroundProvider: BackgroundProvider?): Builder {
            this.backgroundProvider = backgroundProvider
            inlineBackgroundProvider = backgroundProvider
            blockBackgroundProvider = backgroundProvider
            return this
        }

        fun inlineBackgroundProvider(inlineBackgroundProvider: BackgroundProvider?): Builder {
            this.inlineBackgroundProvider = inlineBackgroundProvider
            return this
        }

        fun blockBackgroundProvider(blockBackgroundProvider: BackgroundProvider?): Builder {
            this.blockBackgroundProvider = blockBackgroundProvider
            return this
        }

        /**
         * Configure if `LaTeX` formula should take all available widget width.
         * By default - `true`
         */
        fun blockFitCanvas(blockFitCanvas: Boolean): Builder {
            this.blockFitCanvas = blockFitCanvas
            return this
        }

        fun blockHorizontalAlignment(@JLatexMathDrawable.Align blockHorizontalAlignment: Int): Builder {
            this.blockHorizontalAlignment = blockHorizontalAlignment
            return this
        }

        fun padding(padding: Padding?): Builder {
            this.padding = padding
            inlinePadding = padding
            blockPadding = padding
            return this
        }

        fun inlinePadding(inlinePadding: Padding?): Builder {
            this.inlinePadding = inlinePadding
            return this
        }

        fun blockPadding(blockPadding: Padding?): Builder {
            this.blockPadding = blockPadding
            return this
        }

        fun textColor(@ColorInt textColor: Int): Builder {
            this.textColor = textColor
            return this
        }

        fun inlineTextColor(@ColorInt inlineTextColor: Int): Builder {
            this.inlineTextColor = inlineTextColor
            return this
        }

        fun blockTextColor(@ColorInt blockTextColor: Int): Builder {
            this.blockTextColor = blockTextColor
            return this
        }

        fun build(): JLatexMathTheme {
            return Impl(this)
        }
    }

    internal class Impl(builder: Builder) : JLatexMathTheme() {
        private val textSize: Float
        private val inlineTextSize: Float
        private val blockTextSize: Float
        private val backgroundProvider: BackgroundProvider?
        private val inlineBackgroundProvider: BackgroundProvider?
        private val blockBackgroundProvider: BackgroundProvider?
        private val blockFitCanvas: Boolean

        // horizontal alignment (when there is additional horizontal space)
        private val blockHorizontalAlignment: Int
        private val padding: Padding?
        private val inlinePadding: Padding?
        private val blockPadding: Padding?
        private val textColor: Int
        private val inlineTextColor: Int
        private val blockTextColor: Int

        init {
            textSize = builder.textSize
            inlineTextSize = builder.inlineTextSize
            blockTextSize = builder.blockTextSize
            backgroundProvider = builder.backgroundProvider
            inlineBackgroundProvider = builder.inlineBackgroundProvider
            blockBackgroundProvider = builder.blockBackgroundProvider
            blockFitCanvas = builder.blockFitCanvas
            blockHorizontalAlignment = builder.blockHorizontalAlignment
            padding = builder.padding
            inlinePadding = builder.inlinePadding
            blockPadding = builder.blockPadding
            textColor = builder.textColor
            inlineTextColor = builder.inlineTextColor
            blockTextColor = builder.blockTextColor
        }

        override fun inlineTextSize(): Float {
            return if (inlineTextSize > 0f) {
                inlineTextSize
            } else textSize
        }

        override fun blockTextSize(): Float {
            return if (blockTextSize > 0f) {
                blockTextSize
            } else textSize
        }

        override fun inlineBackgroundProvider(): BackgroundProvider? {
            return inlineBackgroundProvider ?: backgroundProvider
        }

        override fun blockBackgroundProvider(): BackgroundProvider? {
            return blockBackgroundProvider ?: backgroundProvider
        }

        override fun blockFitCanvas(): Boolean {
            return blockFitCanvas
        }

        override fun blockHorizontalAlignment(): Int {
            return blockHorizontalAlignment
        }

        override fun inlinePadding(): Padding? {
            return inlinePadding ?: padding
        }

        override fun blockPadding(): Padding? {
            return blockPadding ?: padding
        }

        override fun inlineTextColor(): Int {
            return if (inlineTextColor != 0) {
                inlineTextColor
            } else textColor
        }

        override fun blockTextColor(): Int {
            return if (blockTextColor != 0) {
                blockTextColor
            } else textColor
        }
    }

    companion object {
        fun create(@Px textSize: Float): JLatexMathTheme {
            return builder(textSize).build()
        }

        fun create(@Px inlineTextSize: Float, @Px blockTextSize: Float): JLatexMathTheme {
            return builder(inlineTextSize, blockTextSize).build()
        }

        fun builder(@Px textSize: Float): Builder {
            return Builder(textSize, 0f, 0f)
        }

        fun builder(@Px inlineTextSize: Float, @Px blockTextSize: Float): Builder {
            return Builder(0f, inlineTextSize, blockTextSize)
        }
    }
}